/*
 * @Date         : 2024-05-20 22:39:25 星期1
 * @Author       : xut
 * @Description  : 在网关层面认证
 */
import { promisify } from "node:util"
import type { Request, Response, NextFunction } from "express"
import jwt from "jsonwebtoken"
import { envConfig } from "../../server/config/default"
import { redisClient } from "../../server/utils/connectRedis"
import { userClient } from "../client"

const grpcGetUser = promisify(userClient.getUser).bind(userClient)

export async function authenticationMiddleware(
  req: Request,
  res: Response,
  next: NextFunction
) {
  const authorization = req.headers["authorization"]

  if (!authorization || typeof authorization !== "string") {
    return res.status(401).end()
  }

  const [type, token] = authorization.split(" ")

  if (type.toLowerCase() !== "bearer") {
    return res.status(401).end()
  }

  const publicKey = Buffer.from(
    envConfig["accessTokenPublicKey"],
    "base64"
  ).toString("ascii")
  const decoded = jwt.verify(token, publicKey) as { sub: string }

  if (!decoded) return res.status(401).end()

  const session = await redisClient.get(decoded.sub)

  if (!session)
    return res
      .status(401)
      .json({ status: "fail", message: "Token has expired" })

  const userId = JSON.parse(session).id as string
  const grpcRes = await grpcGetUser({ id: userId })

  if (!grpcRes?.user) {
    return res
      .status(404)
      .json({ status: "fail", message: 'No User with that ID exists" ' })
  }

  req.user = { id: grpcRes.user.id, role: grpcRes.user.role }

  next()
}
